using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

namespace VisionarySystems.TimeRegi.Model.TimePeriods
{
	public class TimePeriodHost<TKey> : IEnumerable<ITimePeriode>
	{
		#region Private members

		private TimePeriodeID m_ID;

		protected Dictionary<TKey, ITimePeriode> m_TimePeriods = new Dictionary<TKey, ITimePeriode>();
		private static int m_UniqueIndex = 1;

		#endregion

		#region properties

		public TimePeriodeID ID
		{
			get { return m_ID; }
			set { m_ID = value; }
		}

		public TimeSpan WorkedTime
		{
			get
			{
				TimeSpan result = new TimeSpan();
				foreach (ITimePeriode period in m_TimePeriods.Values)
				{
					result = result.Add(period.WorkedTime);
				}
				return result;
			}
		}

		public int TimeSlotCount
		{
			get
			{
				int result = 0;
				foreach (ITimePeriode period in m_TimePeriods.Values)
				{
					result += period.TimeSlotCount;
				}
				return result;
			}
		}

		public int SubClassCount
		{
			get
			{
				int result = 0;
				foreach (ITimePeriode period in m_TimePeriods.Values)
				{
					result += period.SubClassCount + 1;
				}
				return result;
			}
		}

		#endregion

		#region Public Methods

		public static string GetHours(TimeSpan ts)
		{
			return string.Format("{0:D1},{1:D1}", (int)(ts.TotalHours), 10 * ts.Minutes / 60);
		}

		public ITimePeriode GetTimePeriode(TimePeriodeID FindID)
		{
			if (FindID == null)
				throw new ArgumentNullException("FindID is not allowed to be null");
			ITimePeriode result = null;
			if (FindID.Equals(ID))
				result = this as ITimePeriode;
			else
			{
				foreach (ITimePeriode periode in m_TimePeriods.Values)
				{
					result = periode.GetTimePeriode(FindID);
					if (result != null)
						break;
				}
			}
			return result;
		}

		public TreeNode GetNode()
		{
			var result = new TreeNode(ToString()) {Tag = ID};
			foreach (ITimePeriode periode in this)
				result.Nodes.Add(periode.GetNode());
			return result;
		}

		public virtual void Add(TKey Key, ITimePeriode NewPeriod)
		{
			//NewPeriod.ID = GetNextID(NewPeriod);
			m_TimePeriods.Add(Key, NewPeriod);
		}

		protected TimePeriodeID GetNextID(ITimePeriode NewPeriod)
		{
			TimePeriodeID result = new TimePeriodeID(GetUniqueIndex(), NewPeriod.GetTypeID());
			Debug.WriteLine(NewPeriod + ": " + result);
			return result;
		}

		protected int GetUniqueIndex()
		{
			return m_UniqueIndex++;
		}

		public virtual bool AssembleTimeslots(out List<TimeSlot> NewTimeSlots, out List<int> RemovedIndexes)
		{
			bool result = false;
			RemovedIndexes = new List<int>();
			NewTimeSlots = new List<TimeSlot>();
			foreach (ITimePeriode periode in m_TimePeriods.Values)
			{
				List<int> localRemovedIndexes;
				List<TimeSlot> localNewTimeSlots;
				if (periode.AssembleTimeslots(out localNewTimeSlots, out localRemovedIndexes))
				{
					RemovedIndexes.AddRange(localRemovedIndexes);
					NewTimeSlots.AddRange(localNewTimeSlots);
					result = true;
				}
			}
			return result;
		}

		public TimePeriodeType GetTypeID()
		{
			TimePeriodeType result = TimePeriodeType.Unknown;
			if (this is WorkDay)
				result = TimePeriodeType.Workday;
			if (this is WorkWeek)
				result = TimePeriodeType.WorkWeek;
			if (this is WorkYear)
				result = TimePeriodeType.WorkYear;
			return result;
		}

		public TimePeriodeType GetSubTypeID()
		{
			TimePeriodeType result = TimePeriodeType.Unknown;
			if (this is WorkDay)
				result = TimePeriodeType.TimeSlot;
			if (this is WorkWeek)
				result = TimePeriodeType.Workday;
			if (this is WorkYear)
				result = TimePeriodeType.WorkWeek;
			if (this is TimePeriodModel)
				result = TimePeriodeType.WorkYear;
			return result;
		}

		public IEnumerator<ITimePeriode> GetEnumerator()
		{
			foreach (ITimePeriode periode in m_TimePeriods.Values)
				yield return periode;
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			foreach (ITimePeriode periode in m_TimePeriods.Values)
				yield return periode;
		}

		#endregion

	}
}